#pragma once

#include "src/base/Timestamp_v2.h"
#include "src/net/Buffer_v2.h"

#include <functional>
#include <memory>

namespace sola {

using std::placeholders::_1;
using std::placeholders::_2;
using std::placeholders::_3;

template<typename T> inline T* get_pointer(const std::shared_ptr<T>& ptr) {
    return ptr.get();
}

template<typename T> inline T* get_pointer(const std::unique_ptr<T>& ptr) {
    return ptr.get();
}

// Adapted from google-protobuf stubs/common.h

template<typename To, typename From> inline ::std::shared_ptr<To> down_pointer_cast(const ::std::shared_ptr<From>& f) {
    if (false) {
        // implicit_cast<From*, To*>(0);
        static_assert(::std::is_base_of<From, To>::value, "down_pointer_cast requires dynamic_cast to succeed");
        static_cast<To*>(0);
    }

#ifndef NDEBUG
    assert(f == NULL || dynamic_cast<To*>(get_pointer(f)) != NULL);
#endif
    return ::std::static_pointer_cast<To>(f);
}

namespace net {

// All client visible callbacks go here.

// class Buffer;
// class sola::Buffer;
class TcpConnection;
typedef std::shared_ptr<TcpConnection>                       TcpConnectionPtr;
typedef std::function<void()>                                TimerCallback;
typedef std::function<void(const TcpConnectionPtr&)>         ConnectionCallback;
typedef std::function<void(const TcpConnectionPtr&)>         CloseCallback;
typedef std::function<void(const TcpConnectionPtr&)>         WriteCompleteCallback;
typedef std::function<void(const TcpConnectionPtr&, size_t)> HighWaterMarkCallback;

// the data has been read to (buf, len)
typedef std::function<void(const TcpConnectionPtr&, sola::Buffer*, sola::Timestamp)> MessageCallback;

void defaultConnectionCallback(const TcpConnectionPtr& conn);
void defaultMessageCallback(const TcpConnectionPtr& conn, sola::Buffer* buffer, sola::Timestamp receiveTime);

} // namespace net
} // namespace sola
